package com.dps.recommend.config;

import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import com.dps.recommend.beans.DpsSence;
import com.dps.recommend.beans.Group;
import com.dps.recommend.beans.Layer;
import com.dps.recommend.beans.Road;
import com.dps.recommend.enums.DpsAbLoadEnum;
import com.dps.recommend.enums.LayerEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * 配置刷新
 */
@Slf4j
@Component
public class DpsApolloRefreshConfig {
    @Autowired
    private ContextRefresher contextRefresher;
    @Autowired
    private RecProperties recProperties;


    public LinkedHashMap<String, DpsSence> allHashMap = new LinkedHashMap<>();

    /**
     * 监听刷新配置
     *
     * @param changeEvent
     */
    @ApolloConfigChangeListener(value = {"dps_rec_sence"})
    private void onChange(ConfigChangeEvent changeEvent) {
        if (changeEvent.isChanged("rec.config.refresher")) {
            log.info("refresh config start");
            contextRefresher.refresh();
            this.loadLayerProperties();
            log.info("refresh config end");
        }
    }

    @PostConstruct
    private void loadLayerProperties() {
        LinkedHashMap<String, Object> senceListMap = (LinkedHashMap<String, Object>) recProperties.get("sence");
        if (CollectionUtils.isEmpty(senceListMap)) {
            return;
        }

        LinkedHashMap<String, Object> senceList = new LinkedHashMap<>();
        senceList.putAll(senceListMap);
        if (CollectionUtils.isEmpty(senceList)) {
            log.warn("sence not exist!");
            return;
        }
        Iterator<Map.Entry<String, Object>> iterable = senceList.entrySet().iterator();
        LinkedHashMap<String, DpsSence> allHashMapTmp = new LinkedHashMap<>();
        while (iterable.hasNext()) { //场景
            Map.Entry<String, Object> next = iterable.next();
            String senceName = next.getKey();
            LinkedHashMap<String, Object> senceMap = (LinkedHashMap<String, Object>) next.getValue();
            allHashMapTmp.put(senceName, loadGroupProperties(senceMap));
        }
        if (!CollectionUtils.isEmpty(allHashMapTmp)) {
            allHashMap = allHashMapTmp;
        }
    }


    private String getWeight(String dpsAbLoad, String dpsWeight) {
        if (DpsAbLoadEnum.weight.code.equalsIgnoreCase(dpsAbLoad)) {
            if (StringUtils.isEmpty(dpsWeight)) {
                return "10";
            }
            //数字权重
            boolean isNum = dpsWeight.matches("[0-9]+");
            if (!isNum) {
                dpsWeight = "10";
            }
        } else {
            if (StringUtils.isEmpty(dpsWeight)) {
                return "0-100";
            }
            try {
                String[] flows = dpsWeight.split(",");
                for (String flow : flows) {
                    String[] configFlow = flow.split("\\-");
                    if (configFlow.length < 2 || StringUtils.isEmpty(configFlow[0]) || StringUtils.isEmpty(configFlow[1]) || !configFlow[0].matches("[0-9]+") || !configFlow[1].matches("[0-9]+")) {
                        dpsWeight = "0-100";
                        break;
                    }
                }
            } catch (Exception e) {
                dpsWeight = "0-100";
            }
            if (StringUtils.isEmpty(dpsWeight)) {
                dpsWeight = "0-100";
            }
        }
        return dpsWeight;

    }

    /**
     * 加载组的数据
     *
     * @param senceMap
     * @return
     */
    private DpsSence loadGroupProperties(LinkedHashMap<String, Object> senceMap) {
        LinkedHashMap<String, Object> groupList = (LinkedHashMap<String, Object>) senceMap.get("group");
        String dpsAbLoad = (String) senceMap.getOrDefault("dpsAbLoad", DpsAbLoadEnum.weight.code);
        String dpsSenceTime = (String) senceMap.getOrDefault("dpsSenceTime", "300");
        Iterator<Map.Entry<String, Object>> iterable = groupList.entrySet().iterator();
        List<Group> list = new ArrayList<>();
        while (iterable.hasNext()) { //组
            Map.Entry<String, Object> next = iterable.next();
            String groupName = next.getKey();
            LinkedHashMap<String, Object> layerList = (LinkedHashMap<String, Object>) next.getValue();
            String dpsWhiteSwitch = (String) layerList.getOrDefault("dpsWhiteSwitch", "false");
            String dpsWeight = (String) layerList.getOrDefault("dpsWeight", "");
            dpsWeight = getWeight(dpsAbLoad, dpsWeight);
            String dpsWhiteId = (String) layerList.getOrDefault("dpsWhiteId", null);
            Group group = new Group();
            group.setGroupName(groupName);
            group.setDpsWeight(dpsWeight);
            group.setDpsWhiteId(dpsWhiteId);
            group.setDpsWhiteSwitch(dpsWhiteSwitch);
            Arrays.stream(LayerEnum.values()).forEach(layerEnum -> {
                loadProperties(layerList, layerEnum, group);
            });
            list.add(group);
        }

        defaultGroupIntoFirstIndex(list);
        DpsSence dpsSence = new DpsSence();
        dpsSence.setDpsAbLoad(dpsAbLoad);
        dpsSence.setDpsSenceTime(dpsSenceTime);
        dpsSence.setGroupList(list);
        return dpsSence;
    }


    /**
     * 组级别:将default移到第一个的位置
     *
     * @param list
     */
    private void defaultGroupIntoFirstIndex(List<Group> list) {
        Group defaultGroup = list.stream().filter(group -> "default".equalsIgnoreCase(group.getGroupName())).findFirst().orElse(null);
        if (!Objects.isNull(defaultGroup)) {
            list.remove(defaultGroup);
            list.add(0, defaultGroup);
        }
    }

    /**
     * 组级别:将default移到第一个的位置
     *
     * @param list
     */
    private void defaultRoadIntoFirstIndex(List<Road> list) {
        Road defaultRoad = list.stream().filter(road -> "default".equalsIgnoreCase(road.getGroupName())).findFirst().orElse(null);
        if (!Objects.isNull(defaultRoad)) {
            list.remove(defaultRoad);
            list.add(0, defaultRoad);
        }
    }

    /**
     * 构造分层
     *
     * @param group
     * @param layerEnum
     * @return
     */
    private void loadProperties(LinkedHashMap<String, Object> groupValue, LayerEnum layerEnum, Group group) {

        LinkedHashMap layerMap = (LinkedHashMap) groupValue.get(layerEnum.code);
        if (org.springframework.util.CollectionUtils.isEmpty(layerMap)) {
            return;
        }
        Layer layer = new Layer();
        switch (layerEnum) {
            case INIT:
                group.setInit(layer);
                break;
            case RECALL:
                group.setRecall(layer);
                break;
            case MERAGE:
                group.setMerage(layer);
                break;
            case WIDERANK:
                group.setWiderank(layer);
                break;
            case RANK:
                group.setRank(layer);
                break;
            case POSTRANK:
                group.setPostrank(layer);
                break;
            default:
                break;
        }
        List<List<Road>> loadList = loadRoadProperties(layerMap);
        layer.setLayerName(layerEnum.code);
        layer.setDpsTimeOut((String) layerMap.getOrDefault("dpsTimeOut", "2000"));
        layer.setIsParallel((String) layerMap.getOrDefault("isParallel", "true"));
        layer.setDpsLogDebug((String) layerMap.getOrDefault("dpsLogDebug", "false"));
        layerMap.remove("dpsTimeOut");
        layerMap.remove("isParallel");
        layerMap.remove("dpsLogDebug");
        layerMap.remove("road");
        layerMap.remove(layerEnum.code);
        layer.setProperties(layerMap);


        layer.setRoad(loadList);
    }

    /**
     * 构造每路
     *
     * @param layerMap
     * @return
     */
    private List<List<Road>> loadRoadProperties(LinkedHashMap layerMap) {
        List<List<Road>> loadList = new ArrayList<>();
        LinkedHashMap loadMap = (LinkedHashMap) layerMap.get("road");
        loadMap = new LinkedHashMap<>(sortMapFromKey(loadMap));
        Iterator<Map.Entry<String, Object>> iterable = loadMap.entrySet().iterator();
        while (iterable.hasNext()) {
            List<Road> loadDefaultList = new ArrayList<>();
            Map.Entry<String, Object> next = iterable.next();
            String roadIndex = next.getKey();
            LinkedHashMap<String, Object> loadValueList = (LinkedHashMap<String, Object>) next.getValue();
            Iterator<Map.Entry<String, Object>> iterableRoad = loadValueList.entrySet().iterator();
            while (iterableRoad.hasNext()) {
                Map.Entry<String, Object> nextRoad = iterableRoad.next();
                LinkedHashMap<String, Object> loadValueRoadList = (LinkedHashMap<String, Object>) nextRoad.getValue();
                Road road = new Road();
                road.setRoadIndex(roadIndex);
                road.setGroupName(nextRoad.getKey());
                road.setModelName((String) loadValueRoadList.getOrDefault("modelName", null));
                road.setModel((String) loadValueRoadList.getOrDefault("model", null));
                road.setDpsWeight(Double.valueOf(String.valueOf(loadValueRoadList.getOrDefault("dpsWeight", "10"))));
                loadValueRoadList.remove("modelName");
                loadValueRoadList.remove("model");
                loadValueRoadList.remove("dpsWeight");
                road.setProperties(loadValueRoadList);
                loadDefaultList.add(road);
            }
            defaultRoadIntoFirstIndex(loadDefaultList);
            loadList.add(loadDefaultList);
        }
        return loadList;
    }

    //按KEY值升序
    public static Map<String, Object> sortMapFromKey(Map<String, Object> map) {
        Map<String, Object> map2 = new TreeMap<String, Object>(
                new Comparator<String>() {
                    public int compare(String obj1, String obj2) {
                        //升序排序（反过来就是降序排序）
                        return obj1.compareTo(obj2);
                    }
                });
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            map2.put(key, value);
        }
        return map2;
    }

}
